#include <gtk/gtk.h>
#include "master.h"
#include "pvcam.h"

/*
#include <unistd.h>	
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <sys/vfs.h>
#include <termios.h>
#include <time.h>
#include <math.h>
#include <fcntl.h>
#include <errno.h>
*/

static int AcquireQuilt( int16 hCam, int16 num_frames, int16 circ_buff_size, uns32 exp_time );
/* adding hidden parameter for FT cameras */
#define MAKE_FRAME_TRANSFER 2
#define PARAM_FORCE_READOUT_MODE ((CLASS2<<16) + (TYPE_UNS32<<24) + 326)

/* globals */
int16 hcam = -1;
int16 cam_selection = 0;
rs_bool cam_setup = FALSE;
char cam_name[CAM_NAME_LEN];
int16 set_temp = 5000;
int16 temperature;
flt64 readout_time;
int16 num_frames = 1;
int16 circ_buff_size = 4;
uns32 exp_time = 100;
uns32 exp_res = 0;
uns32 exp_mode = TIMED_MODE;
uns32 port = -1;
int16 adc_index = -1;
int16 gain = -1;
uns16 emgain = -1;
rgn_type *region;
uns32 trigger;
uns32 shtr_open_mode;
uns32 pmode;
uns32 logic_output;
rs_bool logic_output_invert;
rs_bool cooling_ctrl;
rs_bool fan_ctrl;
gchar *filename = "test.raw";
GtkWidget *statusbar;

void setROI( rgn_type* roi, uns16 s1, uns16 s2, uns16 sbin, uns16 p1, uns16 p2, uns16 pbin )
{
	roi->s1 = s1;
	roi->s2 = s2;
	roi->sbin = sbin;
	roi->p1 = p1;
	roi->p2 = p2;
	roi->pbin = pbin;
}

void printROI( int16 roi_count, rgn_type* roi )
{
	int i;

	for( i = 0; i < roi_count; i++ ) {
		g_print( "PVCAM rgn_type %i set to { %i, %i, %i, %i, %i, %i }\n", i, roi[i].s1, roi[i].s2, roi[i].sbin, roi[i].p1, roi[i].p2, roi[i].pbin );
	}
}

void setFullFrame( int16 hcam, rgn_type* roi )
{
	uns16 param;

	roi->s1 = 0;
	pl_get_param( hcam, PARAM_SER_SIZE, ATTR_DEFAULT, (void *)&param );
	roi->s2 = param-1;
	roi->sbin = 1;
	roi->p1 = 0;
	pl_get_param( hcam, PARAM_PAR_SIZE, ATTR_DEFAULT, (void *)&param );
	roi->p2 = param-1;
	roi->pbin = 1;
}

void print_pv_error( )
{
	char msg[ERROR_MSG_LEN];
	int16 i;

	i = pl_error_code();
	pl_error_message( i, msg );
	g_print( " [%i]%s\n", i, msg );
}

void set_any_param( int16 hCam, uns32 param_id, void *param_value )
{
	rs_bool b_status, b_param;
	uns16 param_access;

	b_status = pl_get_param( hCam, param_id, ATTR_AVAIL, (void*)&b_param );
	if( b_param ) {
		b_status = pl_get_param( hCam, param_id, ATTR_ACCESS, (void*)&param_access );
		if( param_access == ACC_READ_WRITE || param_access == ACC_WRITE_ONLY ) {
			if( pl_set_param( hCam, param_id, param_value) == PV_FAIL ) {
				g_print( "error: param did not get set\n" );
			}
		}
		else {
			g_print( "error: param is not writable\n" );
		}
	}
	else {
		g_print( "error: param is not available\n" );
	}
}

static gboolean delete_event( GtkWidget *widget,
GdkEvent  *event,
gpointer   data )
{
	gtk_main_quit ();
	return FALSE;
}

static gboolean cbCamOpen( GtkWidget *widget, gpointer data )
{
	g_print( "opening camera %s\n", cam_name );
	if( !pl_cam_open( cam_name, &hcam, OPEN_EXCLUSIVE ) ) print_pv_error();
	else g_print( "camera %s is open\n", cam_name );
}

static gboolean cbCamNameChange( GtkWidget *widget, gpointer data )
{
	gchar* name;

	if( gtk_toggle_button_get_active( widget ) )
		g_print( "radio is active\n" );
	g_print( "current cam_name %s\n", cam_name );
	g_print( "selected cam_name %s\n", (gchar*)data );
	name = g_strdup( (gchar*)data );
	g_print( "current name %s\n", name );

	return 0;
}

static void
update_statusbar (GtkTextBuffer *buffer,
                  GtkStatusbar  *statusbar)
{
  GString *gs;
  int16 temp_current;

  gtk_statusbar_pop( statusbar, 0 ); /* clear any previous message,
				     * underflow is allowed
				     */
  gs = g_string_new( "" );
  pl_get_param( hcam, PARAM_TEMP, ATTR_CURRENT, (void*)&temp_current );
  pl_get_param( hcam, PARAM_READOUT_TIME, ATTR_CURRENT, (void*)&readout_time );
  g_string_sprintf( gs, "Temperature: %d deg. C*100 | Readout Time: %0.2f ms", temp_current, readout_time );

  gtk_statusbar_push( statusbar, 0, gs->str );

  g_string_free( gs, NULL );

  while( gtk_events_pending() ) gtk_main_iteration();
}

static gboolean cbTemperature( GtkWidget *widget, gpointer data )
{
	pl_get_param( hcam, PARAM_TEMP, ATTR_CURRENT, &temperature );
	g_print("current temperature: %d\n", temperature);
	if( pl_set_param( hcam, PARAM_TEMP_SETPOINT, &set_temp ) == PV_FAIL )
		g_print( "PVCAM ERROR : PARAM_TEMP_SETPOINT didn't get set\n" );
	pl_get_param( hcam, PARAM_TEMP_SETPOINT, ATTR_CURRENT, &set_temp );
	g_print("temperature setpoint: %d\n", set_temp);

	return 0;
}

/* Circ Buff and App Buff
	 to be able to store more frames than the circular buffer can hold */
static int AcquireQuilt( int16 hCam, int16 num_frames, int16 circ_buff_size, uns32 exp_time )
{
	uns32 buffer_size, frame_size;
	uns16 *buffer;
	//rgn_type *region;
	uns16 *app_buffer, *pFrame;
	int16 status, i;
	uns32 not_needed;
	void_ptr address;
	uns16 numberframes;
	int16 num_acq;
	FILE *data;

	//setFullFrame( hCam, region );
	//printROI( 1, region );

	num_acq = num_frames;
	numberframes = num_acq;

	/* Init a sequence set the region, exposure mode and exposure time */
	if( pl_exp_init_seq() ) {
		g_print( "experiment sequence initialized\n" );
	} else {
		g_print( "init_seq failed!\n" );
		return PV_FAIL;
	}
	if( pl_exp_setup_cont( hCam, 1, region, exp_mode, exp_time, &frame_size, CIRC_NO_OVERWRITE ) ) {
		g_print( "setup sequence OK\n" );
		g_print( "frame size = %i\n", frame_size );;
        	update_statusbar ("", GTK_STATUSBAR (statusbar));
	} else {
		g_print( "PVCAM ERROR : experiment setup failed!\n" );
		print_pv_error();
		return PV_FAIL;
	}
	/* set up a circular buffer */
	buffer_size = frame_size * circ_buff_size;
	buffer = (uns16*)malloc( buffer_size );
	if( !buffer ) {
		g_print( "memory allocation error!\n" );
		return PV_FAIL;
	}
	else {
		g_print( "frame of data at address %x\n", buffer );
	}

	/* get memory to hold all of data from experiment */
	app_buffer = (uns16*)malloc( frame_size * numberframes );
	if( !app_buffer ) {
		g_print( "error: memory allocation failed\n" );
		return PV_FAIL;
	}
	/* set pointer to beginning of buffer */
	pFrame = app_buffer;

	/* Start the acquisition */
	g_print( "Collecting %i Frames\n", numberframes );
	if( !pl_exp_start_cont( hCam, buffer, buffer_size ) ) {
		print_pv_error();
		free ( buffer );
		free ( app_buffer );
		return PV_FAIL;
	}

	/* ACQUISITION LOOP */
	while( numberframes ) {
		/* wait for data or error */
		while( pl_exp_check_cont_status( hCam, &status, &not_needed,
			&not_needed ) &&
			(status != READOUT_COMPLETE && status != READOUT_FAILED) );

		/* Check Error Codes */
		if( status == READOUT_FAILED ) {
			g_print( "Data collection error: %i\n", pl_error_code() );
			break;
		}

		if ( pl_exp_get_oldest_frame( hCam, &address )) {
			/* address now points to valid data */
			g_print( "Center Three Points: %i, %i, %i at addr: %x\n",
				*((uns16*)address + frame_size/sizeof(uns16)/2 - 1),
				*((uns16*)address + frame_size/sizeof(uns16)/2),
				*((uns16*)address + frame_size/sizeof(uns16)/2 + 1),
				address );
			numberframes--;
			g_print( "Remaining Frames %i\n", numberframes );

			/* copy frame from circular buffer to app buffer */
			memcpy( pFrame, address, frame_size );
			/* set pointer to next frame location */
			pFrame = pFrame + frame_size/sizeof(uns16);

			pl_exp_unlock_oldest_frame( hCam );
		}
	}															 /* End while */

	/* Stop the acquisition */
	pl_exp_stop_cont(hCam,CCS_HALT);

	/* Finish the sequence */
	pl_exp_finish_seq( hCam, buffer, 0);

	/*Uninit the sequence */
	pl_exp_uninit_seq();
	if( buffer )
		free( buffer );

	/* set pointer to beginning of buffer */
	pFrame = app_buffer;
	data = fopen( filename, "wb" );

	for( i = 0; i < num_acq - numberframes; i++ ) {
		/* write the frame to the file */
		fwrite( pFrame, sizeof( uns16 ), frame_size/sizeof(uns16), data );
		/* update the frame pointer to point to the next frame */
		pFrame = pFrame + frame_size/sizeof(uns16);
		g_print( "wrote frame %i\n", i );
	}

	fclose( data );

	if( app_buffer )
		free( app_buffer );

	return PV_OK;
}

static void onAcquire( GtkWidget* w, gpointer data )
{
	GtkWidget* label;
	gchar* text;
	gchar* tmp;
	int16 num_cams;

	pl_cam_get_total( &num_cams );
	g_print( "selected camera is %i\n", hcam );

	if( hcam < 0 || hcam > num_cams ) {
		g_print( "error: Select a Camera\n" );
	}
	else {
		//this is a blocking function, so the Acquire button stays pressed
		//but still queues the clicks =(
		AcquireQuilt( hcam, num_frames, circ_buff_size, exp_time );
	}
}

void AcquireStandard( int16 hCam )
{
	//rgn_type region = { 0, 511, 1, 0, 511, 1 };
	rgn_type region = { 0, 4095, 1, 0, 4095, 1 };
	uns32 size;
	uns16 *frame;
	int16 status;
	uns32 not_needed;
	uns16 numberframes = 1;

	/* Init a sequence set the region, exposure mode and exposure time */
	pl_exp_init_seq();
	pl_exp_setup_seq( hCam, 1, 1, &region, TIMED_MODE, 100, &size );
	//pl_exp_setup_seq( hCam, 1, 1, &region, STROBED_MODE, exp_time_ms, &size );

	frame = (uns16*)malloc( size );

	/* Start the acquisition */
	g_print( "Collecting %i Frames\n", numberframes );

	/* ACQUISITION LOOP */
	while( numberframes ) {
		pl_exp_start_seq(hCam, frame );

		/* wait for data or error */
		while( pl_exp_check_status( hCam, &status, &not_needed ) &&
			(status != READOUT_COMPLETE && status != READOUT_FAILED) );

		/* Check Error Codes */
		if( status == READOUT_FAILED ) {
			g_print( "Data collection error: %i\n", pl_error_code() );
			break;
		}

		/* frame now contains valid data */
		g_print( "Center Three Points: %i, %i, %i\n",
			frame[size/sizeof(uns16)/2 - 1],
			frame[size/sizeof(uns16)/2],
			frame[size/sizeof(uns16)/2 + 1] );
		numberframes--;
		g_print( "Remaining Frames %i\n", numberframes );
	}															 /* End while */

	/* Finish the sequence */
	pl_exp_finish_seq( hCam, frame, 0);

	/*Uninit the sequence */
	pl_exp_uninit_seq();

	free( frame );
}

//TODO: add to pvcam support library
void pvs_version_get( uns16* pv_ver_major, uns16* pv_ver_minor, uns16* pv_ver_trivial ) {
	uns16 pv_ver;

	pl_pvcam_get_ver( &pv_ver );
	*pv_ver_major = (pv_ver & 0xFF00) >> 8;	
	*pv_ver_minor = (pv_ver & 0xF0) >> 4;	
	*pv_ver_trivial = pv_ver & 0xF;	

}
int camtest(void)
{
	char cam_name[CAM_NAME_LEN];

	// parameters for PVCAM library calls
	uns16 shtr_close_delay;
	uns32 logic_output;
	uns32 edge_trigger;
	uns32 readout_mode;
	uns32 temp;

	g_print( "PVCAM init : " );
	if( !pl_pvcam_init() ) {
		g_print( "FAIL\n" );
		return( 0 );
	} else 
		g_print( "OK\n" );

	//get pvcam version
	uns16 maj, min, trivial;
	pvs_version_get( &maj, &min, &trivial );
	g_print( "PVCAM version: %i.%i.%i\n", maj, min, trivial );

	g_print( "PVCAM get cam name : " );
	if( !pl_cam_get_name( cam_selection, cam_name ) ) {
		g_print( "didn't get cam name\n" );
		return( 0 );
	} else 
		g_print( "OK\n  cam name is %s\n", (gchar*)cam_name );
		

	g_print( "PVCAM cam open : " );
	if( !pl_cam_open(cam_name, &hcam, OPEN_EXCLUSIVE ) ) {
		g_print( "camera %s didn't open\n", cam_name );
		return( 0 );
	} else 
		g_print( "OK\n  hcam is %d\n", hcam );

	/* print chip name */
	char chip_name[CCD_NAME_LEN];
	pl_get_param( hcam, PARAM_CHIP_NAME, ATTR_CURRENT, (void*)chip_name );	
	g_print( "PARAM_CHIP_NAME: %s\n", chip_name );


	/* custom parameter for Ed Nather et al. */
	readout_mode = (uns32)MAKE_FRAME_TRANSFER;
	if(!pl_set_param( hcam, PARAM_FORCE_READOUT_MODE, (void*)&readout_mode )) {
		g_print("PVCAM ERROR : PARAM_FORCE_READOUT_MODE didn't get set\n");
		//	return(0);
	}

	region = malloc( sizeof( rgn_type ) );
	setFullFrame( hcam, region );
	printROI(1,region);

	return(1);
}

static gboolean cbCamSelect( GtkWidget *widget, gpointer data )
{
	GtkWidget *dialog;
	GtkWidget *radio;
	GtkWidget *button;
	GSList    *group;
	int16 num_cams;
	int i;

	g_print( "button %s pressed\n", ( gchar* )data );
	dialog=gtk_dialog_new();

	pl_cam_get_total( &num_cams );
	g_print( "total number of cams:%i\n", num_cams );
	
	for( i=0; i<num_cams; i++ ) {
		pl_cam_get_name( i, cam_name );
		g_print( "cam %i: %s\n", i, cam_name );
		if( i == 0 ) {
			radio = gtk_radio_button_new_with_label( NULL, cam_name );
			//group = gtk_radio_button_get_group( GTK_RADIO_BUTTON( radio ) );
			group = gtk_radio_button_group( GTK_RADIO_BUTTON( radio ));
			gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( radio ), TRUE);
		}
		else {
			radio = gtk_radio_button_new_with_label( 
                 			gtk_radio_button_group (GTK_RADIO_BUTTON( radio )),
					cam_name );
		}
		gtk_box_pack_start( GTK_BOX( GTK_DIALOG( dialog )->action_area ), radio, TRUE, TRUE, 0 );
		gtk_widget_show( radio );
		g_signal_connect( G_OBJECT( radio ), "toggled",
			G_CALLBACK( cbCamNameChange ), (gpointer)cam_name );
	}

	button = gtk_button_new_with_label( "Open" );
	gtk_box_pack_start( GTK_BOX( GTK_DIALOG( dialog )->action_area ), button, TRUE, TRUE, 0 );
	g_signal_connect( G_OBJECT( button ), "clicked",
		G_CALLBACK( cbCamOpen ), (gpointer)cam_name );
	gtk_widget_show( button );
	gtk_widget_show( dialog );
	return 0;
}

static gboolean cbEntryFrames( GtkWidget *widget,
GtkWidget *entry )
{
	const gchar *f;
	f = gtk_entry_get_text(GTK_ENTRY ( entry ));
	num_frames = atoi( f );
	g_print("num_frames:%i\n", num_frames );

	return 0;
}

static gboolean cbEntryEMGain( GtkWidget *widget,
GtkWidget *entry )
{
	const gchar *v;
	v = gtk_entry_get_text(GTK_ENTRY ( entry ));
	emgain = atoi( v );

	if( pl_set_param( hcam, PARAM_GAIN_MULT_FACTOR , (void*)&emgain ) == PV_FAIL )
		g_print( "PVCAM ERROR : GAIN MULT FACTOR didn't get set\n" );
	g_print("GAIN MULT FACTOR:%i\n", emgain );
	return 0;
}

static gboolean cbEntryExposure( GtkWidget *widget,
GtkWidget *entry )
{
	const gchar *e;
	e = gtk_entry_get_text(GTK_ENTRY ( entry ));
	exp_time = atoi( e );
	g_print("exp_time:%i\n", exp_time );

	return 0;
}

static gboolean cbEntryVarExposure( GtkWidget *widget,
GtkWidget *entry )
{
	const gchar *e;
	uns16 expt;
	e = gtk_entry_get_text(GTK_ENTRY ( entry ));
	expt = atoi( e );
	g_print("var exp_time:%i\n", expt );
	if( pl_set_param( hcam, PARAM_EXP_TIME , (void*)&expt ) == PV_FAIL )
		g_print( "PVCAM ERROR : EXP TIME didn't get set\n" );
	g_print("EXP TIME:%i\n", expt );

	return 0;
}

static gboolean cbEntryROIS1( GtkWidget *widget,
GtkWidget *entry )
{
	const gchar *e;
	e = gtk_entry_get_text(GTK_ENTRY ( entry ));
	region->s1 = atoi( e );
	g_print("ROI->s1:%i\n", region->s1 );

	return 0;
}

static gboolean cbEntryROIS2( GtkWidget *widget,
GtkWidget *entry )
{
	const gchar *e;
	e = gtk_entry_get_text(GTK_ENTRY ( entry ));
	region->s2 = atoi( e );
	g_print("region->s2:%i\n", region->s2 );

	return 0;
}

static gboolean cbEntryROISbin( GtkWidget *widget,
GtkWidget *entry )
{
	const gchar *e;
	e = gtk_entry_get_text(GTK_ENTRY ( entry ));
	region->sbin = atoi( e );
	g_print("region->sbin:%i\n", region->sbin );

	return 0;
}

static gboolean cbEntryROIP1( GtkWidget *widget,
GtkWidget *entry )
{
	const gchar *e;
	e = gtk_entry_get_text(GTK_ENTRY ( entry ));
	region->p1 = atoi( e );
	g_print("region->p1:%i\n", region->p1 );

	return 0;
}

static gboolean cbEntryROIP2( GtkWidget *widget,
GtkWidget *entry )
{
	const gchar *e;
	e = gtk_entry_get_text(GTK_ENTRY ( entry ));
	region->p2 = atoi( e );
	g_print("region->p2:%i\n", region->p2 );

	return 0;
}

static gboolean cbEntryROIPbin( GtkWidget *widget,
GtkWidget *entry )
{
	const gchar *e;
	e = gtk_entry_get_text(GTK_ENTRY ( entry ));
	region->pbin = atoi( e );
	g_print("region->pbin:%i\n", region->pbin );

	return 0;
}

static gboolean cbSetTemperature( GtkWidget *widget,
GtkWidget *entry )
{
	const gchar *e;
	e = gtk_entry_get_text(GTK_ENTRY ( entry ));
	set_temp = atoi( e );
	g_print("temperature setpoint: %i\n", set_temp );

	return 0;
}

static gboolean cbEntryFilename( GtkWidget *widget,
GtkWidget *entry )
{
	//const gchar *fn;
	filename = gtk_entry_get_text(GTK_ENTRY ( entry ));
	g_print("filename:%s\n", filename );

	return 0;
}

static gboolean cbExpMode( GtkWidget *widget,
GtkWidget *gtkExpMode )
{
	gchar *s;
	s = gtk_combo_box_get_active_text(GTK_COMBO_BOX ( gtkExpMode ));
	if( g_strcmp0( s, "Strobed" ) == 0 )
		exp_mode = STROBED_MODE;
	else if( g_strcmp0( s, "Timed" ) == 0 )
		exp_mode = TIMED_MODE;	
	else if( g_strcmp0( s, "Bulb" ) == 0 )
		exp_mode = BULB_MODE;	
	else if( g_strcmp0( s, "Trigger First" ) == 0 )
		exp_mode = TRIGGER_FIRST_MODE;	
	else if( g_strcmp0( s, "Flash" ) == 0 )
		exp_mode = FLASH_MODE;	
	else if( g_strcmp0( s, "Variable Timed" ) == 0 )
		exp_mode = VARIABLE_TIMED_MODE;	
	else if( g_strcmp0( s, "Int Strobe" ) == 0 )
		exp_mode = INT_STROBE_MODE;	
	g_print("EXP MODE:%s, %d\n", s, exp_mode );
	g_free( s );

	return 0;
}

static gboolean cbPMode( GtkWidget *widget,
GtkWidget *gtkPMode )
{
	gchar *s;
	s = gtk_combo_box_get_active_text(GTK_COMBO_BOX ( gtkPMode ));
	if( g_strcmp0( s, "Normal Parallel Clocking" ) == 0 )
		pmode = PMODE_NORMAL;
	if( g_strcmp0( s, "Frame Transfer Parallel Clocking" ) == 0 )
		pmode = PMODE_FT;
	if( g_strcmp0( s, "Interline" ) == 0 )
		pmode = PMODE_INTERLINE;
	if( g_strcmp0( s, "Kinetics" ) == 0 )
		pmode = PMODE_KINETICS;
	if( g_strcmp0( s, "DIF" ) == 0 )
		pmode = PMODE_DIF;
	if( g_strcmp0( s, "Spectra Kinetics" ) == 0 )
		pmode = PMODE_SPECTRA_KINETICS;
	if( pl_set_param( hcam, PARAM_PMODE, (void*)&pmode ) == PV_FAIL )
		g_print( "PARAM PMODE didn't get set" );
	g_print("PMODE:%s, %d\n", s, pmode );
	g_free( s );

	return 0;
}

static gboolean cbShtrOpenMode( GtkWidget *widget,
GtkWidget *gtkShtrOpenMode )
{
	gchar *s;
	s = gtk_combo_box_get_active_text(GTK_COMBO_BOX ( gtkShtrOpenMode ));
	if( g_strcmp0( s, "Never Open Shutter" ) == 0 )
		shtr_open_mode = OPEN_NEVER;
	else if( g_strcmp0( s, "Image Shift" ) == 0 )
		shtr_open_mode = OPEN_PRE_EXPOSURE;	
	else if( g_strcmp0( s, "Open Shutter Pre-Sequence" ) == 0 )
		shtr_open_mode = OPEN_PRE_SEQUENCE;	
	else if( g_strcmp0( s, "Open Shutter Pre-Trigger" ) == 0 )
		shtr_open_mode = OPEN_PRE_TRIGGER;	
	else if( g_strcmp0( s, "Do Not Change Shutter State" ) == 0 )
		shtr_open_mode = OPEN_NO_CHANGE;	
	if( pl_set_param( hcam, PARAM_SHTR_OPEN_MODE, (void*)&shtr_open_mode ) == PV_FAIL )
		g_print( "PARAM SHTR OPEN MODE didn't get set" );
	g_print("SHTR OPEN MODE:%s, %d\n", s, shtr_open_mode );
	g_free( s );

	return 0;
}

static gboolean cbLogicOutput( GtkWidget *widget,
GtkWidget *gtkLogicOutput )
{
	gchar *s;
	s = gtk_combo_box_get_active_text(GTK_COMBO_BOX ( gtkLogicOutput ));
	//TODO:fill in correct strings
	if( g_strcmp0( s, "Not Scan" ) == 0 )
		logic_output = OUTPUT_NOT_SCAN;
	else if( g_strcmp0( s, "Shutter" ) == 0 )
		logic_output = OUTPUT_SHUTTER;
	else if( g_strcmp0( s, "Not Ready" ) == 0 )
		logic_output = OUTPUT_NOT_RDY;
	else if( g_strcmp0( s, "Logic 0" ) == 0 )
		logic_output = OUTPUT_LOGIC0;
	/*
		logic_output = OUTPUT_CLEARING;
		logic_output = OUTPUT_NOT_FT_IMAGE_SHIFT;
		logic_output = OUTPUT_RESERVED;
		*/
	else if( g_strcmp0( s, "Logic 1" ) == 0 )
		logic_output = OUTPUT_LOGIC1;
	else if( g_strcmp0( s, "Expose (Program'd)" ) == 0 )
		logic_output = OUTPUT_EXPOSE_PROG;
	else if( g_strcmp0( s, "Expose (Effective)" ) == 0 )
		logic_output = OUTPUT_EXPOSE;
	else if( g_strcmp0( s, "Image Shift" ) == 0 )
		logic_output = OUTPUT_IMAGE_SHIFT;
	else if( g_strcmp0( s, "Read Out" ) == 0 )
		logic_output = OUTPUT_READOUT;
	else if( g_strcmp0( s, "Acquiring" ) == 0 )
		logic_output = OUTPUT_ACQUIRING;
	else if( g_strcmp0( s, "Wait For Trigger" ) == 0 )
		logic_output = OUTPUT_WAIT_FOR_TRIG;
		
	if( pl_set_param( hcam, PARAM_LOGIC_OUTPUT, (void*)&logic_output ) == PV_FAIL )
		g_print( "PARAM LOGIC OUTPUT didn't get set" );
	g_print("LOGIC OUTPUT:%s, %d\n", s, logic_output );
	g_free( s );

	return 0;
}

static gboolean cbLogicOutputInvert( GtkWidget *widget,
GtkWidget *gtkLogicOutputInvert )
{
	if( GTK_TOGGLE_BUTTON( widget )->active )
		logic_output_invert = TRUE;
	else
		logic_output_invert = FALSE;	
	if( pl_set_param( hcam, PARAM_LOGIC_OUTPUT_INVERT, (void*)&logic_output_invert ) == PV_FAIL )
		g_print( "PARAM LOGIC OUTPUT INVERT didn't get set\n" );
	g_print( "LOGIC OUTPUT INVERT: %i\n", logic_output_invert );
	
}

static gboolean cbCoolingFanCtrl( GtkWidget *widget,
GtkWidget *gtkCoolingFanCtrl )
{
	if( GTK_TOGGLE_BUTTON( widget )->active )
		fan_ctrl = TRUE;
	else
		fan_ctrl = FALSE;	
	if( pl_set_param( hcam, PARAM_LOGIC_OUTPUT_INVERT, (void*)&fan_ctrl ) == PV_FAIL )
		g_print( "PARAM COOLING FAN CTRL didn't get set\n" );
	g_print( "COOLING FAN CTRL: %i\n", fan_ctrl );
	
}

static gboolean cbExpRes( GtkWidget *widget,
GtkWidget *gtkExpMode )
{
	gchar *s;
	s = gtk_combo_box_get_active_text(GTK_COMBO_BOX ( gtkExpMode ));
//{ EXP_RES_ONE_MILLISEC, EXP_RES_ONE_MICROSEC, EXP_RES_ONE_SEC };
	if( g_strcmp0( s, "One Millisecond Exposure Resolution" ) == 0 )
		exp_res = EXP_RES_ONE_MILLISEC;
	else if( g_strcmp0( s, "One Microsecond Exposure Resolution" ) == 0 )
		exp_res = EXP_RES_ONE_MICROSEC;
	if( pl_set_param( hcam, PARAM_EXP_RES_INDEX, (void*)&exp_res ) == PV_FAIL )
		g_print( "PARAM EDGE TRIGGER didn't get set" );
	g_print("EXP RES:%s, %d\n", s, exp_res );
	g_free( s );

	return 0;
}

static gboolean cbEdgeTrigger( GtkWidget *widget,
GtkWidget *gtkEdgeTrigger )
{
	gchar *s;
	s = gtk_combo_box_get_active_text(GTK_COMBO_BOX ( gtkEdgeTrigger ));
	if( g_strcmp0( s, "+ edge" ) == 0 )
		trigger = EDGE_TRIG_POS;
	else if( g_strcmp0( s, "- edge" ) == 0 )
		trigger = EDGE_TRIG_NEG;
	if( pl_set_param( hcam, PARAM_EDGE_TRIGGER, (void*)&trigger ) == PV_FAIL )
		g_print( "PARAM EDGE TRIGGER didn't get set" );
	g_print("EDGE TRIGGER:%s, %d\n", s, trigger );
	g_free( s );

	return 0;
} 

static gboolean cbPort( GtkWidget *widget,
GtkWidget *gtkPort )
{
	gchar *s;
	uns32 port_set;
	s = gtk_combo_box_get_active_text(GTK_COMBO_BOX ( gtkPort ));
	if( g_strcmp0( s, "Multiplication Gain" ) == 0 )
		port_set = READOUT_PORT_MULT_GAIN;
	else if( g_strcmp0( s, "NORMAL" ) == 0 )
		port_set = READOUT_PORT_NORMAL;
	else if( g_strcmp0( s, "Low Noise" ) == 0 )
		port_set = READOUT_PORT_LOW_NOISE;
	else if( g_strcmp0( s, "High Capacity" ) == 0 )
		port_set = READOUT_PORT_HIGH_CAP;
	if( pl_set_param( hcam, PARAM_READOUT_PORT, (void*)&port_set ) == PV_FAIL )
		g_print( "PARAM READOUT PORT didn't get set\n" );
	else
	       	port = port_set;
	g_print("READOUT PORT:%s, port value:%d\n", s, port );
	g_free( s );

	return 0;
}

static gboolean cbGain( GtkWidget *widget,
GtkWidget *gtkGain )
{
	gchar *s;
	s = gtk_combo_box_get_active_text(GTK_COMBO_BOX ( gtkGain ));
	if( g_strcmp0( s, "1" ) == 0 )
		gain = 1;
	else if( g_strcmp0( s, "2" ) == 0 )
		gain = 2;
	else if( g_strcmp0( s, "3" ) == 0 )
		gain = 3;
	if( pl_set_param( hcam, PARAM_GAIN_INDEX, (void*)&gain ) == PV_FAIL )
		g_print( "PARAM GAIN INDEX didn't get set\n" );
	g_print("GAIN INDEX:%d\n", gain );
	g_free( s );

	return 0;
}

static gboolean cbADC( GtkWidget *widget,
GtkWidget *gtkADC )
{
	gchar *s;
	s = gtk_combo_box_get_active_text(GTK_COMBO_BOX ( gtkADC ));
	if( g_str_has_prefix( s, "0" ) == TRUE ) {
		adc_index = 0;
	} else if( g_str_has_prefix( s, "1" ) == TRUE ) {
		adc_index = 1;
	} else if( g_str_has_prefix( s, "2" ) == TRUE ) {
		adc_index = 2;
	} else if( g_str_has_prefix( s, "3" ) == TRUE ) {
		adc_index = 3;
	}
	if( pl_set_param( hcam, PARAM_SPDTAB_INDEX, (void*)&adc_index ) == PV_FAIL )
		g_print( "PARAM SPDTAB INDEX didn't get set\n" );
	g_print("SPDTAB INDEX:%s\n", s );
	g_free( s );

        update_statusbar ("", GTK_STATUSBAR (statusbar));
	return 0;
}

int main( int argc, char* argv[] ) {
	GtkWidget* window;
	GtkWidget* button;
	GtkWidget* box_h;
	GtkWidget* box_v;
	GtkWidget* entryExposure;
	GtkWidget* entryVarExposure;
	GtkWidget* entryEMGain;
	GtkWidget* entryFilename;
	GtkWidget* entryFrames;
	GtkWidget* entryTemperature;
	GtkWidget* entryROIS1;
	GtkWidget* entryROIS2;
	GtkWidget* entryROISbin;
	GtkWidget* entryROIP1;
	GtkWidget* entryROIP2;
	GtkWidget* entryROIPbin;
	GtkWidget* label;
	GString *gs;
	int16 i=0, j=0, port_count=0, port_min=0, port_max=0;
	uns32 enum_value=0, enum_default=0, enum_count=0;
	uns32 param_access=0;
	uns16 uns16_param=0;
	char enum_string[100];	


	gtk_init( &argc, &argv );

	window=gtk_window_new( GTK_WINDOW_TOPLEVEL );
	gtk_window_set_title( GTK_WINDOW( window ), "PVCAM GTK" );
	//gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);

	g_signal_connect( G_OBJECT( window ), "delete_event",
		G_CALLBACK( delete_event ), NULL );

	gtk_container_set_border_width( GTK_CONTAINER( window ), 5 );

	box_v = gtk_vbox_new( FALSE, 0 );
	gtk_container_add( GTK_CONTAINER( window ), box_v );

	box_h = gtk_hbox_new( FALSE, 0 );
	gtk_container_add( GTK_CONTAINER( box_v ), box_h );

/* Select button */
	//Init PVCAM and Open ONE camera 
	button = gtk_button_new_with_label( "Select" );
	g_signal_connect( G_OBJECT( button ), "clicked",
		G_CALLBACK( cbCamSelect ), (gpointer) "Select" );
	gtk_box_pack_start( GTK_BOX( box_h ), button, TRUE, TRUE, 0 );
	gtk_widget_show( button );

/* acquire button */
	button = gtk_button_new_with_label( "Acquire" );
	g_signal_connect( G_OBJECT( button ), "clicked",
		G_CALLBACK( onAcquire ), (gpointer) "Acquire" );
	gtk_box_pack_start( GTK_BOX( box_h ), button, TRUE, TRUE, 0 );
	gtk_widget_show( button );

	button = gtk_button_new_with_label( "Temperature" );
	gtk_box_pack_start( GTK_BOX( box_h ), button, TRUE, TRUE, 0 );
	gtk_widget_show( button );
	g_signal_connect( G_OBJECT( button ), "clicked",
		G_CALLBACK( cbTemperature ), (gpointer) "Temperature" );

/* temperature button */
	label = gtk_label_new( "Temperature - Degrees C * 100" );
	gtk_box_pack_start( GTK_BOX( box_v ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );

	entryTemperature = gtk_entry_new();
	gtk_entry_set_max_length( GTK_ENTRY( entryTemperature ), 50);
	gtk_box_pack_start( GTK_BOX( box_v ), entryTemperature, TRUE, TRUE, 0 );
	gtk_widget_show( entryTemperature );
	g_signal_connect( G_OBJECT( entryTemperature ),
		"activate",
		G_CALLBACK( cbSetTemperature ),
		entryTemperature );

/* exposure time entry */
	label = gtk_label_new( "Exposure Time" );
	gtk_box_pack_start( GTK_BOX( box_v ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );

	entryExposure = gtk_entry_new();
	gtk_entry_set_max_length( GTK_ENTRY( entryExposure ), 50);
	gtk_box_pack_start( GTK_BOX( box_v ), entryExposure, TRUE, TRUE, 0 );
	gtk_widget_show( entryExposure );
	g_signal_connect( G_OBJECT( entryExposure ),
		"activate",
		G_CALLBACK( cbEntryExposure ),
		entryExposure );

/* exposure time units */

/* on line exposure for use with exp mode variable timed */
	label = gtk_label_new( "Variable Exposure Time" );
	gtk_box_pack_start( GTK_BOX( box_v ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );

	entryVarExposure = gtk_entry_new();
	gtk_entry_set_max_length( GTK_ENTRY( entryVarExposure ), 50);
	gtk_box_pack_start( GTK_BOX( box_v ), entryVarExposure, TRUE, TRUE, 0 );
	gtk_widget_show( entryVarExposure );
	g_signal_connect( G_OBJECT( entryVarExposure ),
		"activate",
		G_CALLBACK( cbEntryVarExposure ),
		entryVarExposure );


/* frames entry */
	label = gtk_label_new( "Number of Frames" );
	gtk_box_pack_start( GTK_BOX( box_v ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );

	entryFrames = gtk_entry_new();
	gtk_entry_set_max_length( GTK_ENTRY( entryFrames ), 50);
	gtk_box_pack_start( GTK_BOX( box_v ), entryFrames, TRUE, TRUE, 0 );
	gtk_widget_show( entryFrames );
	g_signal_connect( G_OBJECT( entryFrames ),
		"activate",
		G_CALLBACK( cbEntryFrames ),
		entryFrames );

/* filename entry */
	label = gtk_label_new( "Filename" );
	gtk_box_pack_start( GTK_BOX( box_v ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );

	entryFilename = gtk_entry_new();
	gtk_entry_set_max_length( GTK_ENTRY( entryFilename ), 50);
	gtk_box_pack_start( GTK_BOX( box_v ), entryFilename, TRUE, TRUE, 0 );
	gtk_widget_show( entryFilename );
	g_signal_connect( G_OBJECT( entryFilename ),
		"activate",
		G_CALLBACK( cbEntryFilename ),
		entryFilename );

/* Initialize the PVCam Library */
	if( camtest() == PV_FAIL ) {
		//if( pl_pvcam_init() == PV_FAIL ) 
		g_print( "Can not initiallize PVCAM\n" );
		print_pv_error();
		gtk_main_quit (); //FAIL
		return PV_FAIL;
	}

/* adc */
	GtkWidget *expander_adc;
	expander_adc = gtk_expander_new( "ADC" );
	gtk_box_pack_start( GTK_BOX( box_v ), expander_adc, FALSE, FALSE, 0 );
	GtkWidget *adc_frame, *adc_box;
	//make the adc_frame
	adc_frame = gtk_frame_new( "ADC" );
	//pack the adc_frame
	//gtk_box_pack_start( GTK_BOX( box_v ), adc_frame, FALSE, FALSE, 0 );
	//make the box
	
	adc_box = gtk_vbox_new (FALSE, 0);
    	gtk_container_set_border_width( GTK_CONTAINER( adc_box ), 5 );
	//add the box to the adc_frame

	gtk_container_add(GTK_CONTAINER (adc_frame), adc_box);
    	gtk_container_set_border_width( GTK_CONTAINER( expander_adc ), 5 );
	gtk_container_add(GTK_CONTAINER (expander_adc), adc_frame);

	/* Port */
	//make add pack show connect
	label = gtk_label_new( "Port" );
    	gtk_container_add (GTK_CONTAINER (adc_box), label);
	gtk_box_pack_start( GTK_BOX( adc_box ), label, FALSE, FALSE, 0 );
	gtk_widget_show( label );
	//make port combo
	GtkWidget *comboboxPort;
	comboboxPort = gtk_combo_box_new_text();

	gs = g_string_new( "" );
	g_string_assign( gs, "" );
	pl_get_param( hcam, PARAM_READOUT_PORT, ATTR_COUNT, (void*)&port_count );
	g_print( "number of port(s): %d\n", port_count );
	//if port count is 1 and param is read only, then just make the one combo
	param_access = 0;
	pl_get_param( hcam, PARAM_READOUT_PORT, ATTR_ACCESS, (void*)&param_access );
	g_print( "readout port access is %d\n", param_access );
	pl_get_param( hcam, PARAM_READOUT_PORT, ATTR_DEFAULT, (void*)&enum_default );
	g_print( "the default port is %d\n", enum_default );
	if( param_access == ACC_READ_ONLY ) {
		g_print( "readout port is read only\n" );

		pl_get_enum_param( hcam, PARAM_READOUT_PORT, 0, &enum_value, enum_string, 100 );
		g_string_sprintf( gs, "%s", (gchar*)enum_string );
		gtk_combo_box_append_text( comboboxPort, gs->str );	
		gtk_combo_box_set_active( comboboxPort, 0 );
	} else {
		for( j=0; j<port_count; j++ ) {
			port = j;
			pl_get_enum_param( hcam, PARAM_READOUT_PORT, port, &enum_value, enum_string, 100 );
			if( pl_set_param( hcam, PARAM_READOUT_PORT, (void*)&enum_value) == PV_OK ) {
				g_print("port index: %d, value: %d, string: %s\n", port, enum_value, (gchar*)enum_string );
				g_string_sprintf( gs, "%s", (gchar*)enum_string );
				gtk_combo_box_append_text( comboboxPort, gs->str );	
			} else {
				g_print( "PVCAM ERROR : PARAM_READOUT_PORT didn't get set\n" );
			}
			//pl_get_param( hcam, PARAM_READOUT_PORT, ATTR_DEFAULT, (void*)&enum_default );
			g_print( "the default should not change %d\n", enum_default );
			if( enum_value == enum_default ) {
				g_print( "PVCAM PARAM READOUT PORT DEFAULT: %d\n", enum_default );
			//	g_print( "default readout port is %d\n", enum_default );
				//this is the default port, set jth control to default
				gtk_combo_box_set_active( comboboxPort, j );
			}
		}
	}
	// TODO find default and set it so the GUI is consistant
	uns32 param_default;
	pl_get_param( hcam, PARAM_READOUT_PORT, ATTR_DEFAULT, (void*)&param_default );
	// BUG need to set the index, not the param_default value
	g_print( "PVCAM PARAM READOUT PORT DEFAULT: %d\n", param_default );
	gtk_combo_box_set_active( comboboxPort, 0 );
    	gtk_container_add (GTK_CONTAINER (adc_box), comboboxPort);
	gtk_box_pack_start( GTK_BOX( adc_box ), comboboxPort, TRUE, TRUE, 0 );
	gtk_widget_show( comboboxPort );
	g_signal_connect( G_OBJECT( comboboxPort ),
		"changed",
		G_CALLBACK( cbPort ),
		comboboxPort );
	/* TODO - refresh speed and gain after port is selected */
	/*		- also rebuild the control ( if you can ) */

	/* Speed Index */
	label = gtk_label_new( "ADC Rate" );
    	gtk_container_add (GTK_CONTAINER (adc_box), label);
	gtk_box_pack_start( GTK_BOX( adc_box ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	GtkWidget *comboboxADC;
	comboboxADC = gtk_combo_box_new_text();
	int16 spdtab_i=0, spdtab_min=0, spdtab_max=0, spdtab_count=0, spdtab_default=0;
	uns16 pix_time=0;
	uns32 readout_port=0;
	pl_get_param( hcam, PARAM_READOUT_PORT, ATTR_MIN, (void*)&port_min );
	pl_get_param( hcam, PARAM_READOUT_PORT, ATTR_MAX, (void*)&port_max );
	pl_get_param( hcam, PARAM_READOUT_PORT, ATTR_COUNT, (void*)&port_count );
	//g_print( "port min: %d, port max %d, port count %d\n", port_min, port_max, port_count );
	//try and set port, if OK, create control for spdtab_index list
	for( j=0; j<port_count; j++ ) {
		pl_get_enum_param( hcam, PARAM_READOUT_PORT, j, &readout_port, enum_string, 100 );
		if( pl_set_param( hcam, PARAM_READOUT_PORT, (void*)&readout_port) == PV_OK ) {

			pl_get_param( hcam, PARAM_SPDTAB_INDEX, ATTR_DEFAULT, (void*)&spdtab_default );
			pl_get_param( hcam, PARAM_SPDTAB_INDEX, ATTR_MIN, (void*)&spdtab_min );
			pl_get_param( hcam, PARAM_SPDTAB_INDEX, ATTR_MAX, (void*)&spdtab_max );
			pl_get_param( hcam, PARAM_SPDTAB_INDEX, ATTR_COUNT, (void*)&spdtab_count );
			g_print("spdtab min: %d, max %d, count %d\n", spdtab_min, spdtab_max, spdtab_count );
			for( i=0; i<spdtab_count; i++ ) {
				pl_set_param( hcam, PARAM_SPDTAB_INDEX, (void*)&i );
				pl_get_param( hcam, PARAM_PIX_TIME, ATTR_CURRENT, (void*)&pix_time );
				g_print("spdtab index: %d, pix time: %d ns", i, pix_time );
				g_print(", pix frequency( MHz ): %.3f\n", (float)1e3/pix_time );
				g_string_sprintf( gs, "%d index, %d port, %.3f MHz", i, readout_port, (float)1e3/pix_time );
				gtk_combo_box_append_text( comboboxADC, gs->str );	
				if( spdtab_default = i )
					gtk_combo_box_set_active( comboboxADC, i );
			}
		} else {
			if( param_access == ACC_READ_ONLY ) {
				//just loop for each spd_tab
				pl_get_param( hcam, PARAM_SPDTAB_INDEX, ATTR_DEFAULT, (void*)&spdtab_default );
				pl_get_param( hcam, PARAM_SPDTAB_INDEX, ATTR_COUNT, (void*)&spdtab_count );
				for( i=0; i<spdtab_count; i++ ) {
					pl_set_param( hcam, PARAM_SPDTAB_INDEX, (void*)&i );
					pl_get_param( hcam, PARAM_PIX_TIME, ATTR_CURRENT, (void*)&pix_time );
					g_print("spdtab index: %d, pix time: %d", i, pix_time );
					g_print(", pix frequency( MHz ): %.3f\n", (float)1e3/pix_time );
					g_string_sprintf( gs, "%d index, %d port, %.3f MHz", i, readout_port, (float)1e3/pix_time );
					gtk_combo_box_append_text( comboboxADC, gs->str );	
					if( spdtab_default = i )
						gtk_combo_box_set_active( comboboxADC, i );
				}

			} else {
				g_print( "PVCAM ERROR : PARAM_READOUT_PORT didn't get set\n" );
			}
		}
	}
	
	
	gtk_combo_box_set_active( comboboxADC, 0 );
    	gtk_container_add (GTK_CONTAINER (adc_box), comboboxADC);
	gtk_box_pack_start( GTK_BOX( adc_box ), comboboxADC, TRUE, TRUE, 0 );
	gtk_widget_show( comboboxADC );
	g_signal_connect( G_OBJECT( comboboxADC ),
		"changed",
		G_CALLBACK( cbADC ),
		comboboxADC );
	
	/* Gain */
	//TODO this is hardcoded to 1-3, bad!
	label = gtk_label_new( "Gain" );
    	gtk_container_add (GTK_CONTAINER (adc_box), label);
	gtk_box_pack_start( GTK_BOX( adc_box ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	GtkWidget *comboboxGain;
	comboboxGain = gtk_combo_box_new_text();
	gtk_combo_box_append_text( comboboxGain, "1" );	
	gtk_combo_box_append_text( comboboxGain, "2" );	
	gtk_combo_box_append_text( comboboxGain, "3" );	
	gtk_combo_box_set_active( comboboxGain, 0 );
    	gtk_container_add (GTK_CONTAINER (adc_box), comboboxGain);
	gtk_box_pack_start( GTK_BOX( adc_box ), comboboxGain, TRUE, TRUE, 0 );
	gtk_widget_show( comboboxGain );
	g_signal_connect( G_OBJECT( comboboxGain ),
		"changed",
		G_CALLBACK( cbGain ),
		comboboxGain );
	/* EM Gain */
	//TODO if param not available, disable control, show "not available" in display
	//     or maybe not even make the control.
	label = gtk_label_new( "GAIN MULT FACTOR" );
	gtk_box_pack_start( GTK_BOX( adc_box ), label, TRUE, TRUE, 0 );

	entryEMGain = gtk_entry_new();
	gtk_entry_set_max_length( GTK_ENTRY( entryEMGain ), 50);
	gtk_box_pack_start( GTK_BOX( adc_box ), entryEMGain, TRUE, TRUE, 0 );
	g_signal_connect( G_OBJECT( entryEMGain ),
		"activate",
		G_CALLBACK( cbEntryEMGain ),
		entryEMGain );
	pl_get_param( hcam, PARAM_GAIN_MULT_FACTOR, ATTR_AVAIL, (void*)&uns16_param );
	if( uns16_param ) {
		gtk_widget_show( label );
		gtk_widget_show( entryEMGain );
	}
	//gtk_widget_show( adc_frame );
/* rgn_type */
	//frame
	GtkWidget *expander_roi;
	expander_roi = gtk_expander_new( "ROI" );
	gtk_box_pack_start( GTK_BOX( box_v ), expander_roi, FALSE, FALSE, 0 );


	GtkWidget *roi_frame, *roi_box;
	roi_frame = gtk_frame_new( "ROI" );
	//gtk_box_pack_start( GTK_BOX( box_v ), roi_frame, FALSE, FALSE, 0 );
	roi_box = gtk_vbox_new (FALSE, 0);
    	gtk_container_set_border_width( GTK_CONTAINER( roi_box ), 5 );
	gtk_container_add(GTK_CONTAINER ( roi_frame ), roi_box);
    	gtk_container_set_border_width( GTK_CONTAINER( expander_roi ), 5 );
	gtk_container_add(GTK_CONTAINER ( expander_roi ), roi_frame );

	label = gtk_label_new( "S 1 ( serial start pixel )" );
    		gtk_container_add (GTK_CONTAINER (roi_box), label);
	gtk_box_pack_start( GTK_BOX( roi_box ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	entryROIS1 = gtk_entry_new();
    	gtk_container_add (GTK_CONTAINER (roi_box), entryROIS1);
	gtk_entry_set_max_length( GTK_ENTRY( entryROIS1 ), 6);
	gtk_box_pack_start( GTK_BOX( roi_box ), entryROIS1, TRUE, TRUE, 0 );
	gtk_widget_show( entryROIS1 );
	g_signal_connect( G_OBJECT( entryROIS1 ),
		"activate",
		G_CALLBACK( cbEntryROIS1 ),
		entryROIS1 );

	label = gtk_label_new( "S 2 ( serial stop pixel )" );
    		gtk_container_add (GTK_CONTAINER (roi_box), label);
	gtk_box_pack_start( GTK_BOX( roi_box ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	entryROIS2 = gtk_entry_new();
    	gtk_container_add (GTK_CONTAINER (roi_box), entryROIS2);
	gtk_entry_set_max_length( GTK_ENTRY( entryROIS2 ), 6);
	gtk_box_pack_start( GTK_BOX( roi_box ), entryROIS2, TRUE, TRUE, 0 );
	gtk_widget_show( entryROIS2 );
	g_signal_connect( G_OBJECT( entryROIS2 ),
		"activate",
		G_CALLBACK( cbEntryROIS2 ),
		entryROIS2 );

	label = gtk_label_new( "S bin ( serial binning )" );
	gtk_box_pack_start( GTK_BOX( roi_box ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	entryROISbin = gtk_entry_new();
	gtk_container_add (GTK_CONTAINER (roi_box), entryROISbin);
	gtk_entry_set_max_length( GTK_ENTRY( entryROISbin ), 6);
	gtk_box_pack_start( GTK_BOX( roi_box ), entryROISbin, TRUE, TRUE, 0 );
	gtk_widget_show( entryROISbin );
	g_signal_connect( G_OBJECT( entryROISbin ),
		"activate",
		G_CALLBACK( cbEntryROISbin ),
		entryROISbin );


	label = gtk_label_new( "P 1 ( parallel start row )" );
	gtk_box_pack_start( GTK_BOX( roi_box ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	entryROIP1 = gtk_entry_new();
    	gtk_container_add (GTK_CONTAINER (roi_box), entryROIP1);
	gtk_entry_set_max_length( GTK_ENTRY( entryROIP1 ), 6);
	gtk_box_pack_start( GTK_BOX( roi_box ), entryROIP1, TRUE, TRUE, 0 );
	gtk_widget_show( entryROIP1 );
	g_signal_connect( G_OBJECT( entryROIP1 ),
		"activate",
		G_CALLBACK( cbEntryROIP1 ),
		entryROIP1 );


	label = gtk_label_new( "P 2 ( parallel stop row )" );
	gtk_box_pack_start( GTK_BOX( roi_box ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	entryROIP2 = gtk_entry_new();
    	gtk_container_add (GTK_CONTAINER (roi_box), entryROIP2);
	gtk_entry_set_max_length( GTK_ENTRY( entryROIP2 ), 6);
	gtk_box_pack_start( GTK_BOX( roi_box ), entryROIP2, TRUE, TRUE, 0 );
	gtk_widget_show( entryROIP2 );
	g_signal_connect( G_OBJECT( entryROIP2 ),
		"activate",
		G_CALLBACK( cbEntryROIP2 ),
		entryROIP2 );

	label = gtk_label_new( "P bin ( parallel binning )" );
	gtk_box_pack_start( GTK_BOX( roi_box ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	entryROIPbin = gtk_entry_new();
    	gtk_container_add (GTK_CONTAINER (roi_box), entryROIPbin);
	gtk_entry_set_max_length( GTK_ENTRY( entryROIPbin ), 6);
	gtk_box_pack_start( GTK_BOX( roi_box ), entryROIPbin, TRUE, TRUE, 0 );
	gtk_widget_show( entryROIPbin );
	g_signal_connect( G_OBJECT( entryROIPbin ),
		"activate",
		G_CALLBACK( cbEntryROIPbin ),
		entryROIPbin );

/* set entry boxes to defaults */
	g_string_sprintf( gs, "%d", num_frames );
	gtk_entry_set_text( GTK_ENTRY( entryFrames ), gs->str );
	g_string_assign( gs, "" );
	g_string_sprintf( gs, "%d", exp_time );
	gtk_entry_set_text( GTK_ENTRY( entryExposure ), gs->str );
	g_string_assign( gs, filename );
	gtk_entry_set_text( GTK_ENTRY( entryFilename ), gs->str );
/* use NVRAM default for Temperature */
	g_string_assign( gs, "" );
	pl_get_param( hcam, PARAM_TEMP_SETPOINT, ATTR_DEFAULT, &set_temp );
	g_string_sprintf( gs, "%d", set_temp );
	g_print( "PVCAM TEMP_SETPOINT : %d\n", set_temp );
	gtk_entry_set_text( GTK_ENTRY( entryTemperature ), gs->str );
	/* EM gain default */
	g_string_assign( gs, "" );
	pl_get_param( hcam, PARAM_GAIN_MULT_FACTOR, ATTR_DEFAULT, &emgain );
	g_string_sprintf( gs, "%d", emgain );
	g_print( "PVCAM GAIN_MULT_FACTOR : %d\n", emgain );
	gtk_entry_set_text( GTK_ENTRY( entryEMGain ), gs->str );


/* build trigger controls */
/* exposure resolution */

	label = gtk_label_new( "Exposure Time Units" );
	gtk_box_pack_start( GTK_BOX( box_v ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	GtkWidget *comboboxExpRes;
	comboboxExpRes = gtk_combo_box_new_text();
	g_string_assign( gs, "" );
	pl_get_param( hcam, PARAM_EXP_RES, ATTR_COUNT, (void*)&enum_count );
	g_print( "number of exp res(s): %d\n", enum_count );
	for( j=0; j<enum_count; j++ ) {
		if( pl_get_enum_param( hcam, PARAM_EXP_RES, j, &enum_value, enum_string, 100 ) == PV_OK ) {
			g_print("index: %d, value: %d, string: %s\n", j, enum_value, (gchar*)enum_string );
			g_string_sprintf( gs, "%s", (gchar*)enum_string );
			gtk_combo_box_append_text( comboboxExpRes, gs->str );	
		} else {
			g_print( "PVCAM ERROR : PARAM_EXP_RES didn't get set\n" );
		}
//TODO locate and set default
		pl_get_param( hcam, PARAM_EXP_RES, ATTR_DEFAULT, (void*)&enum_default );
		if( enum_value == enum_default )
			g_print( "PVCAM PARAM EXP RES DEFAULT: %d\n", enum_default );
	}

	gtk_combo_box_set_active( comboboxExpRes, 0 );
	gtk_box_pack_start( GTK_BOX( box_v ), comboboxExpRes, TRUE, TRUE, 0 );
	gtk_widget_show( comboboxExpRes );
	g_signal_connect( G_OBJECT( comboboxExpRes ),
		"changed",
		G_CALLBACK( cbExpRes ),
		comboboxExpRes );
/* exposure mode */
	label = gtk_label_new( "Exposure Mode" );
	gtk_box_pack_start( GTK_BOX( box_v ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	GtkWidget *comboboxExpMode;
	comboboxExpMode = gtk_combo_box_new_text();

	g_string_assign( gs, "" );
	pl_get_param( hcam, PARAM_EXPOSURE_MODE, ATTR_COUNT, (void*)&enum_count );
	g_print( "number of exposure mode(s): %d\n", enum_count );
	for( j=0; j<enum_count; j++ ) {
		if( pl_get_enum_param( hcam, PARAM_EXPOSURE_MODE, j, &enum_value, enum_string, 100 ) == PV_OK ) {
		//if( pl_set_param( hcam, PARAM_EXPOSURE_MODE, (void*)&enum_value) == PV_OK ) 
			g_print("index: %d, value: %d, string: %s\n", j, enum_value, (gchar*)enum_string );
			g_string_sprintf( gs, "%s", (gchar*)enum_string );
			gtk_combo_box_append_text( comboboxExpMode, gs->str );	
		} else {
			g_print( "PVCAM ERROR : PARAM_EXPOSURE_MODE didn't get set\n" );
		}
//TODO locate and set default
		pl_get_param( hcam, PARAM_EDGE_TRIGGER, ATTR_DEFAULT, (void*)&enum_default );
		if( enum_value == enum_default )
			g_print( "PVCAM PARAM EXP MODE DEFAULT: %d\n", enum_default );
	}

	//TODO locate and set default
	gtk_combo_box_set_active( comboboxExpMode, 0 );
	gtk_box_pack_start( GTK_BOX( box_v ), comboboxExpMode, TRUE, TRUE, 0 );
	gtk_widget_show( comboboxExpMode );
	g_signal_connect( G_OBJECT( comboboxExpMode ),
		"changed",
		G_CALLBACK( cbExpMode ),
		comboboxExpMode );
/* p mode */
	label = gtk_label_new( "Parallel Mode" );
	gtk_box_pack_start( GTK_BOX( box_v ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	GtkWidget *comboboxPMode;
	comboboxPMode = gtk_combo_box_new_text();


	g_string_assign( gs, "" );
	pl_get_param( hcam, PARAM_PMODE, ATTR_COUNT, (void*)&enum_count );
	g_print( "number of p mode(s): %d\n", enum_count );
	for( j=0; j<enum_count; j++ ) {
		if( pl_get_enum_param( hcam, PARAM_PMODE, j, &enum_value, enum_string, 100 ) == PV_OK ) {
		//if( pl_set_param( hcam, PARAM_PMODE, (void*)&enum_value) == PV_OK ) 
			g_print("index: %d, value: %d, string: %s\n", j, enum_value, (gchar*)enum_string );
			g_string_sprintf( gs, "%s", (gchar*)enum_string );
			gtk_combo_box_append_text( comboboxPMode, gs->str );	
		} else {
			g_print( "PVCAM ERROR : PARAM_PMODE didn't get set\n" );
		}
	}

	//TODO locate and set default
	gtk_combo_box_set_active( comboboxPMode, 0 );
	gtk_box_pack_start( GTK_BOX( box_v ), comboboxPMode, TRUE, TRUE, 0 );
	gtk_widget_show( comboboxPMode );
	g_signal_connect( G_OBJECT( comboboxPMode ),
		"changed",
		G_CALLBACK( cbPMode ),
		comboboxPMode );
/* shtr open mode */
	label = gtk_label_new( "Shutter Open Mode" );
	gtk_box_pack_start( GTK_BOX( box_v ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	GtkWidget *comboboxShtrOpenMode;
	comboboxShtrOpenMode = gtk_combo_box_new_text();


	//uns32 enum_count;
	g_string_assign( gs, "" );
	pl_get_param( hcam, PARAM_SHTR_OPEN_MODE, ATTR_COUNT, (void*)&enum_count );
	g_print( "number of shutter mode(s): %d\n", enum_count );
	for( j=0; j<enum_count; j++ ) {
		if( pl_get_enum_param( hcam, PARAM_SHTR_OPEN_MODE, j, &enum_value, enum_string, 100 ) == PV_OK ) {
		//if( pl_set_param( hcam, PARAM_EXPOSURE_MODE, (void*)&enum_value) == PV_OK ) 
			g_print("index: %d, value: %d, string: %s\n", j, enum_value, (gchar*)enum_string );
			g_string_sprintf( gs, "%s", (gchar*)enum_string );
			gtk_combo_box_append_text( comboboxShtrOpenMode, gs->str );	
		} else {
			g_print( "PVCAM ERROR : PARAM_EXPOSURE_MODE didn't get set\n" );
		}
	}

	//TODO locate and set default
	gtk_combo_box_set_active( comboboxShtrOpenMode, 0 );
	gtk_box_pack_start( GTK_BOX( box_v ), comboboxShtrOpenMode, TRUE, TRUE, 0 );
	gtk_widget_show( comboboxShtrOpenMode );
	g_signal_connect( G_OBJECT( comboboxShtrOpenMode ),
		"changed",
		G_CALLBACK( cbShtrOpenMode ),
		comboboxShtrOpenMode );
/* logic output */
	label = gtk_label_new( "Logic Output" );
	gtk_box_pack_start( GTK_BOX( box_v ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	GtkWidget *comboboxLogicOutput;
	comboboxLogicOutput = gtk_combo_box_new_text();


	//uns32 enum_count;
	g_string_assign( gs, "" );
	pl_get_param( hcam, PARAM_LOGIC_OUTPUT, ATTR_COUNT, (void*)&enum_count );
	g_print( "number of logic out(s): %d\n", enum_count );
	for( j=0; j<enum_count; j++ ) {
		if( pl_get_enum_param( hcam, PARAM_LOGIC_OUTPUT, j, &enum_value, enum_string, 100 ) == PV_OK ) {
			g_print("index: %d, value: %d, string: %s\n", j, enum_value, (gchar*)enum_string );
			g_string_sprintf( gs, "%s", (gchar*)enum_string );
			gtk_combo_box_append_text( comboboxLogicOutput, gs->str );	
		} else {
			g_print( "PVCAM ERROR : PARAM_EXPOSURE_MODE didn't get set\n" );
		}
	}

	//TODO locate and set default
	gtk_combo_box_set_active( comboboxLogicOutput, 0 );
	gtk_box_pack_start( GTK_BOX( box_v ), comboboxLogicOutput, TRUE, TRUE, 0 );
	gtk_widget_show( comboboxLogicOutput );
	g_signal_connect( G_OBJECT( comboboxLogicOutput ),
		"changed",
		G_CALLBACK( cbLogicOutput ),
		comboboxLogicOutput );
//if invert is availabe, add checkbox control
	rs_bool hasa_logic_invert;
	if( pl_get_param( hcam, PARAM_LOGIC_OUTPUT_INVERT, ATTR_AVAIL, (void*)&hasa_logic_invert ) ) {
		g_print("\nlogic invert availability is %i\n", hasa_logic_invert );
		g_print("\nlogic invert availability is %x\n", hasa_logic_invert );
		if( hasa_logic_invert ) {
			label = gtk_label_new( "Logic Output Invert" );
			gtk_box_pack_start( GTK_BOX( box_v ), label, TRUE, TRUE, 0 );
			gtk_widget_show( label );
			GtkWidget *checkLogicOutputInvert;
			checkLogicOutputInvert = gtk_check_button_new_with_mnemonic( "_Invert" );
			gtk_box_pack_start( GTK_BOX( box_v ), checkLogicOutputInvert, TRUE, TRUE, 0 );
			gtk_widget_show( checkLogicOutputInvert );
			g_signal_connect( checkLogicOutputInvert, "toggled",
					G_CALLBACK( cbLogicOutputInvert ), checkLogicOutputInvert );
		} else {
			g_print("\nno logic invert\n" );
		}
	} else {
		g_print("\nPVCAM get param FAILED\n");
		print_pv_error();
	}

//if cooling fan control is availabe, add checkbox control
	rs_bool hasa_cooling_fan_ctrl;
	if ( pl_get_param( hcam, PARAM_COOLING_FAN_CTRL, ATTR_AVAIL, (void*)&hasa_cooling_fan_ctrl ) ) {
		
		g_print("\ncooling fan ctrl availability is %i\n", hasa_cooling_fan_ctrl );
		g_print("\ncooling fan ctrl availability is %x\n", hasa_cooling_fan_ctrl );
		if( hasa_cooling_fan_ctrl ) {
			label = gtk_label_new( "Cooling Fan Control" );
			gtk_box_pack_start( GTK_BOX( box_v ), label, TRUE, TRUE, 0 );
			gtk_widget_show( label );
			GtkWidget *checkCoolingFanCtrl;
			checkCoolingFanCtrl = gtk_check_button_new_with_mnemonic( "_Cooling Fan Control" );
			gtk_box_pack_start( GTK_BOX( box_v ), checkCoolingFanCtrl, TRUE, TRUE, 0 );
			gtk_widget_show( checkCoolingFanCtrl );
			g_signal_connect( checkCoolingFanCtrl, "toggled",
					G_CALLBACK( cbCoolingFanCtrl ), checkCoolingFanCtrl );
		} else {
			g_print("\nno cooling fan\n\n");
		}
	} else {
		g_print("\nPVCAM get param FAILED\n");
		print_pv_error();
	}
	
/* trigger polarity */
	uns32 edge_trigger;
	label = gtk_label_new( "Edge Trigger" );
	gtk_box_pack_start( GTK_BOX( box_v ), label, TRUE, TRUE, 0 );
	gtk_widget_show( label );
	GtkWidget *comboboxEdgeTrigger;
	comboboxEdgeTrigger = gtk_combo_box_new_text();
	g_string_assign( gs, "" );
	pl_get_param( hcam, PARAM_EDGE_TRIGGER, ATTR_COUNT, (void*)&enum_count );
	g_print( "number of trigger mode(s): %d\n", enum_count );
	for( j=0; j<enum_count; j++ ) {
		if( pl_get_enum_param( hcam, PARAM_EDGE_TRIGGER, j, &enum_value, enum_string, 100 ) == PV_OK ) {
			g_print("index: %d, value: %d, string: %s\n", j, enum_value, (gchar*)enum_string );
			g_string_sprintf( gs, "%s", (gchar*)enum_string );
			gtk_combo_box_append_text( comboboxEdgeTrigger, gs->str );	
		} else {
			g_print( "PVCAM ERROR : PARAM_EDGE_TRIGGER didn't get set\n" );
		}
//TODO set default
		pl_get_param( hcam, PARAM_EDGE_TRIGGER, ATTR_DEFAULT, (void*)&enum_default );
		if( enum_value == enum_default )
			g_print( "PVCAM PARAM EDGE TRIGGER DEFAULT: %d\n", enum_default );
	}
	gtk_combo_box_set_active( comboboxEdgeTrigger, 0 );
	gtk_box_pack_start( GTK_BOX( box_v ), comboboxEdgeTrigger, TRUE, TRUE, 0 );
	gtk_widget_show( comboboxEdgeTrigger );
	g_signal_connect( G_OBJECT( comboboxEdgeTrigger ),
		"changed",
		G_CALLBACK( cbEdgeTrigger ),
		comboboxEdgeTrigger );

/* set entry boxes to defaults */
	g_string_assign( gs, "" );
	g_string_sprintf( gs, "%d", num_frames );
	gtk_entry_set_text( GTK_ENTRY( entryFrames ), gs->str );
	g_string_assign( gs, "" );
	g_string_sprintf( gs, "%d", exp_time );
	gtk_entry_set_text( GTK_ENTRY( entryExposure ), gs->str );
	g_string_assign( gs, filename );
	gtk_entry_set_text( GTK_ENTRY( entryFilename ), gs->str );
	/* temperature from ATTR_DEFAULT */
	pl_get_param( hcam, PARAM_TEMP_SETPOINT, ATTR_DEFAULT, &set_temp );
	g_string_assign( gs, "" );
	g_string_sprintf( gs, "%d", set_temp );
	g_print( "PVCAM TEMP_SETPOINT : %d\n", set_temp );
	gtk_entry_set_text( GTK_ENTRY( entryTemperature ), gs->str );
	/* EM gain */
	g_string_assign( gs, "" );
	pl_get_param( hcam, PARAM_GAIN_MULT_FACTOR, ATTR_DEFAULT, &emgain );
	g_string_sprintf( gs, "%d", emgain );
	g_print( "PVCAM GAIN_MULT_FACTOR : %d\n", emgain );
	gtk_entry_set_text( GTK_ENTRY( entryEMGain ), gs->str );
	/* region */
	g_string_assign( gs, "" );
	g_string_sprintf( gs, "%d", region->s1 );
	gtk_entry_set_text( GTK_ENTRY( entryROIS1 ), gs->str );
	g_string_assign( gs, "" );
	g_string_sprintf( gs, "%d", region->s2 );
	gtk_entry_set_text( GTK_ENTRY( entryROIS2 ), gs->str );
	g_string_assign( gs, "" );
	g_string_sprintf( gs, "%d", region->sbin );
	gtk_entry_set_text( GTK_ENTRY( entryROISbin ), gs->str );
	g_string_assign( gs, "" );
	g_string_sprintf( gs, "%d", region->p1 );
	gtk_entry_set_text( GTK_ENTRY( entryROIP1 ), gs->str );
	g_string_assign( gs, "" );
	g_string_sprintf( gs, "%d", region->p2 );
	gtk_entry_set_text( GTK_ENTRY( entryROIP2 ), gs->str );
	g_string_assign( gs, "" );
	g_string_sprintf( gs, "%d", region->pbin );
	gtk_entry_set_text( GTK_ENTRY( entryROIPbin ), gs->str );

/* Create statusbar */
      GtkTextBuffer *buffer;
      statusbar = gtk_statusbar_new ();
      gtk_box_pack_start( GTK_BOX( box_v ), statusbar, TRUE, TRUE, 0 );
      gtk_widget_show( statusbar );
        update_statusbar ("", GTK_STATUSBAR (statusbar));

	g_string_free( gs, NULL );

	gtk_widget_show( expander_adc );
	gtk_widget_show( expander_roi );
	gtk_widget_show( adc_frame );
	gtk_widget_show( adc_box );
	gtk_widget_show( roi_frame );
	gtk_widget_show( roi_box );
	gtk_widget_show( box_v );
	gtk_widget_show( box_h );
	gtk_widget_show( window );


	gtk_main();

	g_print( "cleanup pvcam\n" );
	g_print( "PVCAM close hCam %d: ", hcam );
	if( !pl_cam_close( hcam ) ) 
		g_print( "FAIL\n" );
	else 
		g_print( "OK\n" );
	
	g_print( "PVCAM uninit : " );
	if( !pl_pvcam_uninit() ) 
		g_print( "FAIL\n" );
	else 
		g_print( "OK\n" );

	pl_pvcam_uninit();
	if( region )
		free( region );
	return 0;
}

